import sys
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_tcp
import cv2
import numpy as np
import socket
import struct
import time
import redis
#import datatime
import configparser

def main():
    config = configparser.ConfigParser()
    config.read('config.ini')

    server_host = config.get('server', 'host', fallback='localhost').strip("'").strip('"')
    server_port = config.getint('server', 'port', fallback=8080)
    device_host = config.get('device', 'device_host', fallback='localhost').strip("'").strip('"')
    device_port = config.getint('device', 'device_port', fallback=502)
    device_slave_id = config.getint('device', 'slave_id', fallback=1)
    device_reg_addr = config.getint('device', 'reg_addr', fallback=1)
    redis_url = config.get('redis', 'url', fallback='redis://127.0.0.1/').strip("'").strip('"')
    plc_io_url = config.get('PLC', 'io_url', fallback='/sensor').strip("'").strip('"')
    plc_set_string = config.get('PLC', 'set_string', fallback='1').strip("'").strip('"')
    plc_reset_string = config.get('PLC', 'reset_string', fallback='0').strip("'").strip('"')
    camera_channel = config.getint('camera', 'channel', fallback=0)
    camera_interval = config.getint('camera', 'interval', fallback=5) / 1000

    print(f"server: {server_host}:{server_port}")
    print(f"device: {device_host}:{device_port}")

    r = redis.Redis.from_url(redis_url)
    last_value = r.get(plc_io_url)
    print(f"io_url: {plc_io_url}")
    last_value = last_value.decode('utf-8') if last_value is not None else plc_reset_string
    print(f"last_value {last_value}")
    print(f"plc_set_string is {plc_set_string}")
    iteration = 0

    server_url = f"{server_host}:{server_port}"
    stream = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    stream.connect((server_host, server_port))
    print("Server connected")
    master = modbus_tcp.TcpMaster(host=device_host, port=device_port)
    slave_value=master.execute(device_slave_id,cst.READ_DISCRETE_INPUTS,device_reg_addr,1)
    print(f'slave_value ={slave_value[0]}')
   # def connect_server(server_host,server_port,number):
    #    for _ in range(number):
     #       try:
      #          stream = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
       #         stream.connect((server_host,server.port))
        #        print('server connect')
         #   except ConnectionRefusedError:
          #      print('Connect refused ,Server is not available')
           # except Exception as e:
            #    print(f'AN error occured:{str(e)}')

    #number = 5
    #connect_server(server_host,server_port,number)

    cam = cv2.VideoCapture(camera_channel)
    cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

    while True:
        while True:
            # value = r.get(plc_io_url)
            # value = value.decode('utf-8') if value is not None else plc_reset_string
            #print(f"value: {value}")
            #print(f"time={time.time()}")
            slave_value=master.execute(device_slave_id,cst.READ_DISCRETE_INPUTS,device_reg_addr,1)
            value = slave_value[0]
            #print(f"value: {value} last_value: {last_value}")
            if str(last_value) != plc_set_string and str(value) == plc_set_string:
                last_value = value
                print(f"{time.time()}IO change from reset to set, trigger sending images")
                break
            last_value = value
            cam.read()
            time.sleep(camera_interval)

        stream.send(struct.pack('>H', 1))
        iteration += 1
        print(f"{time.time()}   Send images, iteration: {iteration}")

        for _ in range(1):
            ret, frame = cam.read()
            if not ret:
                continue

            _, buf = cv2.imencode(".jpg", frame)
            buf_size = len(buf)
            stream.send(struct.pack('>I', buf_size))
            stream.send(buf)
            print(f"{time.time()}   buf_size={buf_size}")

if __name__ == '__main__':
    while True:
        try:
            main()
        except  Exception as e:
            print(f"sleep 10s after exception: {e}")
            time.sleep(10)
